use async_trait::async_trait;
use futures::{Future, TryFutureExt};
use russh::server::{Auth, Session};
use russh::*;
use russh_keys::*;
use std::io::Read;
use std::sync::Arc;

pub struct Client {}

#[async_trait]
impl client::Handler for Client {
    type Error = anyhow::Error;

    async fn check_server_key(
        self,
        server_public_key: &key::PublicKey,
    ) -> Result<(Self, bool), Self::Error> {
        println!("check_server_key: {:?}", server_public_key);
        Ok((self, true))
    }

    async fn data(
        self,
        channel: ChannelId,
        data: &[u8],
        session: client::Session,
    ) -> Result<(Self, client::Session), Self::Error> {
        println!(
            "data on channel {:?}: {:?}",
            channel,
            std::str::from_utf8(data)
        );
        Ok((self, session))
    }
}

pub async fn start() {
    let config = russh::client::Config::default();
    let config = Arc::new(config);
    let sh = Client {};

    let mut session = russh::client::connect(config, ("192.168.1.157", 22), sh)
        .await
        .unwrap();
    if session
        .authenticate_password("isms", "itc123")
        .await
        .unwrap()
    {
        println!("open session channel");

        let mut channel = session.channel_open_session().await.unwrap();
        // channel.request_shell(true).await.unwrap();
        // let mode: (Pty, u32) = (Pty::VEOF, 1);
        // let terminal_modes: [(Pty, u32); 1] = [mode];
        // channel
        //     .request_pty(true, "xterm", 100, 100, 100, 100, &terminal_modes)
        //     .await
        //     .unwrap();

        let _ = channel.request_shell(true).await.unwrap();
        let mode_1: (Pty, u32) = (Pty::ECHO, 0);
        // let mode_2: (Pty, u32) = (Pty::ECHOCTL, 1);
        // let mode_3: (Pty, u32) = (Pty::TTY_OP_END, 1);
        // let mode_4: (Pty, u32) = (Pty::VEOF, 1);
        let terminal_modes = [mode_1];
        let _ = channel
            .request_pty(true, "xterm", 80, 24, 100, 100, &terminal_modes)
            .await
            .unwrap();
        println!("data ...");
        channel.data(&b"ls"[..]).await.unwrap();
        println!("data over, waitting msg ...");
        if let Some(msg) = channel.wait().await {
            println!("{:?}", msg)
        }
    }
}
